/*
 * Copyright (c) 2024. Lorem ipsum dolor sit amet, consectetur adipiscing elit.
 * Morbi non lorem porttitor neque feugiat blandit. Ut vitae ipsum eget quam lacinia accumsan.
 * Etiam sed turpis ac ipsum condimentum fringilla. Maecenas magna.
 * Proin dapibus sapien vel ante. Aliquam erat volutpat. Pellentesque sagittis ligula eget metus.
 * Vestibulum commodo. Ut rhoncus gravida arcu.
 */

package com.scujj.cs6.service.impl;


import com.qcloud.cos.model.*;
import com.scujj.cs6.common.BusinessException;
import com.scujj.cs6.common.ErrorCode;
import com.scujj.cs6.common.Result;
import com.scujj.cs6.config.CosClientConfig;
import com.scujj.cs6.manager.CosManager;
import com.scujj.cs6.model.vo.FileVo;
import com.scujj.cs6.service.FileService;
import com.scujj.cs6.service.UserService;
import jakarta.servlet.http.HttpServletRequest;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.RandomStringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;
import java.io.*;
import java.nio.file.Files;
import java.util.Base64;


/**
 * 文件服务
 *
 * @author FlanChan
 * @version 1.0
 * @createDate 2024-12-10 16:14:50
 */
@Service
@Slf4j
@RequiredArgsConstructor
public class FileServiceImpl implements FileService {

    private final UserService userService;

    private final CosClientConfig cosClientConfig;

    private final CosManager cosManager;

    /**
     * 上传文件
     *
     * @param multipartFile 文件
     * @param request       HTTP请求
     * @return {@link FileVo}
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public Result<FileVo> uploadAvatar(MultipartFile multipartFile, HttpServletRequest request) {
        Long userId = (Long) request.getAttribute("user");

        return uploadImage(multipartFile, userId);
    }

    private Result<FileVo> uploadImage(String base64Str, Long userId) {
        if (base64Str == null || base64Str.isBlank() || base64Str.isEmpty()) {
            throw new BusinessException(ErrorCode.PARAM_ERROR, "base64字符串不能为空");
        }

        if (!base64Str.matches("^data:image/\\w+;base64,.+")) {
            throw new BusinessException(ErrorCode.PARAM_ERROR, "base64字符串格式错误，必须为图片");
        }

        // 文件目录：根据业务、用户来划分
        String uuid = RandomStringUtils.randomAlphanumeric(8);
        String contentType = base64Str.substring(base64Str.indexOf(":") + 1, base64Str.indexOf(";"));
        String extension = "." + contentType.substring(contentType.indexOf("/") + 1);
        String base64ImageStr = base64Str.substring(base64Str.indexOf(",") + 1);
        String filename = uuid + extension;
        String filepath = String.format("user_avatar/%s/%s", userId, filename);
        log.info("file path = {}", filepath);
        String url = cosClientConfig.getCosHost() + '/' + filepath;
        File file = null;

        try {
            // 上传文件
            file = File.createTempFile(filename, null);

            Base64.Decoder decoder = Base64.getDecoder();
            byte[] imgbytes = decoder.decode(base64ImageStr);
            for (int i = 0; i < imgbytes.length; ++i) {
                if (imgbytes[i] < 0) {
                    imgbytes[i] += 256;
                }
            }

            // 保存图片
            OutputStream out = new FileOutputStream(file);
            out.write(imgbytes);
            out.flush();
            out.close();

            long usableSpace = file.getUsableSpace();

            boolean putObjectResult = cosManager.putObject(filepath, file);
            if (!putObjectResult) {
                throw new BusinessException(ErrorCode.PARAM_ERROR, "文件上传失败");
            }
            FileVo fileVo = new FileVo();
            fileVo.setFileName(filename);
            fileVo.setUrl(url);
            fileVo.setType(contentType);
            // 更新用户头像
            String deleteOldAvatar = userService.updateUserAvatar(userId, url);
            if (deleteOldAvatar != null)  {
                cosManager.deleteObject(deleteOldAvatar);
            }
            // 返回可访问地址
            return Result.success(fileVo);
        } catch (Exception e) {
            log.error("file upload error, filepath = " + filepath, e);
            return Result.error(ErrorCode.SERVER_ERROR, "文件上传失败");
        } finally {
            if (file != null) {
                // 删除临时文件
                boolean delete = file.delete();
                if (!delete) {
                    log.error("file delete error, filepath = {}", filepath);
                }
            }
        }
    }

    private Result<FileVo> uploadImage(MultipartFile multipartFile, Long userId) {
        if (multipartFile.isEmpty()) {
            throw new BusinessException(ErrorCode.PARAM_ERROR, "文件不能为空");
        }

        final String contentType = multipartFile.getContentType();
        if (contentType == null || !contentType.startsWith("image")) {
            throw new BusinessException(ErrorCode.PARAM_ERROR,"文件类型错误，必须为图片");
        }

        // 文件目录：根据业务、用户来划分
        String uuid = RandomStringUtils.randomAlphanumeric(8);
        String extension = '.' + multipartFile.getOriginalFilename().substring(multipartFile.getOriginalFilename().lastIndexOf(".") + 1);
        String filename = uuid + extension;
        String filepath = String.format("user_avatar/%s/%s", userId, filename);
        String url = cosClientConfig.getCosHost() + '/' + filepath;
        File file = null;

        try {
            // 上传文件
            file = File.createTempFile(filepath, null);
            multipartFile.transferTo(file);
            log.info("file path = {}", file.getPath());
            boolean putObjectResult = cosManager.putObject(filepath, file);
            if (!putObjectResult) {
                throw new BusinessException(ErrorCode.PARAM_ERROR, "文件上传失败");
            }
            FileVo fileVo = new FileVo();
            fileVo.setFileName(filename);
            fileVo.setUrl(url);
            fileVo.setType(multipartFile.getContentType());
            log.info("file upload success, filepath = {}", filepath);
            // 更新用户头像
            String deleteOldAvatar = userService.updateUserAvatar(userId, url);
            if (deleteOldAvatar != null)  {
                cosManager.deleteObject(deleteOldAvatar);
            }
            // 返回可访问地址
            return Result.success(fileVo);
        } catch (Exception e) {
            log.error("file upload error, filepath = " + filepath, e);
            return Result.error(ErrorCode.SERVER_ERROR, "文件上传失败");
        } finally {
            // 释放内存
            System.gc();
            if (file != null) {
                // 删除临时文件
                boolean delete = file.delete();
                if (!delete) {
                    log.error("file delete error, filepath = {}", filepath);
                }
            }
        }
    }

    @Override
    public Result<FileVo> uploadAvatar(String base64Str, HttpServletRequest request) {
        Long userId = (Long) request.getAttribute("user");

        return uploadImage(base64Str,userId);
    }
}
